
-- FIXME: timer precision is only 1/10 seconds

local stty = require[[stty]]
local slot = require[[slot]]

local mt = {}
mt.__index = mt

mt.new = function()
	return setmetatable({
		_stty = stty.new[[-echo -icanon min 0 time 1]],
		_on_timeout = slot.new(),
		_now = 0,
		on_button_press = slot.new(),
	}, mt)
end

mt.now = function(this)
	return this._now / 10
end

mt.run = function(this)
	this._cont = true
	while this._cont do
		local x = io.read(1)
		local t = this:now()
		local timed_out = function(m) return t >= m end

		this._on_timeout:put_if(timed_out, t)
		this._on_timeout:unlisten_if(timed_out, t)

		if x then
			if x:byte() == 4
			then this:quit()		-- ^D received
			else this.on_button_press:put(t, x)
			end
		end

		this._now = this._now + 1
	end
	this._now = 0
end

mt.quit = function(this)
	this._cont = nil
end

mt.timeout = function(this, listener, duration)
	if duration == nil
	then this._on_timeout:unlisten(listener)
	else this._on_timeout(listener, this:now() + duration)
	end
end

return mt

--[=[

=head1 NAME

C<async>: asynchronous io library

=head1 SYNOPSIS

	local async = require[[async]]
	local a = async.new()

	a:run()
	a:quit()
	a.on_button_press <- slot
	a:timeout(listener, duration)
	a:timeout(listener)

=head1 SEE ALSO

L<slot>

=cut

--]=]

